#pragma once
#include "VisioCommon.h"
#include "freeglut.h"
#include "Meshes.h"
#include "MeshInstances.h"
#include "OpenCV.h"
#include "ViewerCamera.h"
#include "Camera.h"
#include "ImageMatch.h"
#include "BundlerParser.h"
#include "PointCloud.h"
#include "SfmPool.h"
#include "ImageDataBase.h"
#include "TrackDataBase.h"
#include "Matcher.h"

#include <vector>


using namespace std;

struct SNewCamAddingParams
{
	UINT index;
	VisiblePointsVector SharedVisiablePoints;
};

typedef std::vector<SNewCamAddingParams> CamAddingParamsVector;

class CCVApp
{
public:

	//viewer methods
	void Init(CCameraMesh* pCamMesh);
	inline void IncreaseNumberOfPhotos() {m_NumberOfPhotos++; CONSOLE("Number of photos: %d\n", m_NumberOfPhotos);}
	inline void DecreaseNumberOfPhotos() {m_NumberOfPhotos = (m_NumberOfPhotos > 2) ? m_NumberOfPhotos - 1 : m_NumberOfPhotos; CONSOLE("Number of photos: %d\n", m_NumberOfPhotos);}
	
	void Reset();
	

	//photo stich methods
	void RunPhotoStich(char* SceneParams);
	void Create3DScenesFromOrderedPhotos();


	//load or create data methods
	void CreateImageAndTracksDataBase(char* SceneParams);
	void CreateImageAndTracksDataBaseInternal();
	void ImportImageAndTracksFromBundler(char* SceneParams);
	ImageNamesVector LoadImagesNames();
	ImageNamesVector LoadImagesNames(char* ImageFileName);
	void LoadImages();

	// get the initial params
	CCamera* InitCanonicalCamera(CImageData* pImageData);
	CamerasVector GetIntialCameraPair(CImageMatch* pMatch);
	UINT InitiliazeFirstPair(CamerasVector& cameras, CPointCloud& PointCloud);
	UINT RegisterFirstPair(CamerasVector& Cameras, CPointCloud& PointCloud);

	//Main algorithm function
	UINT RegisterNextCam(CamerasVector& Cameras, CPointCloud& PointCloud);
	bool InitiliazeNextBestCamera(CamerasVector& Cameras, CPointCloud& PointCloud);
	UINT GetNextCamIndex( VisiblePointsVector& VisablePoints );
	CCamera* EstimateNewCam(UINT index, VisiblePointsVector& SharedVisablePoints, CamerasVector& Cameras, CPointCloud& PointCloud);
	//others
	bool IsImageAlreadyAdded(UINT index) const;
	CameraIndexVector GetImageIndexVector(CamerasVector& cams) const;
	//given an EMatrix of a camera pair and assuming the first camera is canonical returns the params of the second one
	SCameraParams CCVApp::GetCameraParamsFromEMatrix(Mat EMatrix, double focal, CImageMatch* pMatch) const;
	CCameraMesh* GetCameraMesh() const;
	CCamera* FindFirstEstimationOfNewCam( UINT index,const VisiblePointsVector& SharedVisablePoints,const CPointCloud& PointCloud, SInliners& inliners );
	CamAddingParamsVector GetNextCams(VisiblePointsVector SharedVisiblePoints, UINT index);
	void DumpOutputToFile(const char* OutFileName);
	void LoadMeshes(vector<CMeshInstance*>* pMeshes);
	static FILE* GetImageFile(const char* SceneName, char* mode);
	void DumpImageFile(const char* OutFileName);
	char* GetStringFromFile(FILE* pFile, char* str);
	string GetSceneName(string SceneParamsFile);
	Mat GetCorrectConfiguration(Mat& t, Mat Ra, Mat Rb, Mat K, CImageMatch* pMatch) const;
	string GetSceneDirectory(string SceneParamsFile);
private:
	CImageDataBase m_ImageDataBase;
	CTrackDataBase m_TrackDataBase;


	CImageMatcher m_IMatcher;
	
	CamerasVector m_Cameras;
	CPointCloud m_PointCloud;
	CSfmPool m_SfmPool;
	ImagesVector m_Images;

	//maximum number of image to register
	UINT m_NumberOfPhotos;

	//current number of images registered
	UINT m_NumCamera;


	
	bool m_bUsePreloadedMatches;

	vector<CMesh*> m_Meshes;
	vector<CMeshInstance*> m_MeshInstances;

	string m_SceneName;
	string m_SceneDirectory;
};
